package com.water.guider

import android.app.Activity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import java.util.*

/**
 * 新手引导指示器.
 */
class Guider(builder: Builder) {

    companion object {
        const val TAG = "Guider"
        const val MODE_NEXT = 0
        const val MODE_TOGETHER = 1
    }

    private var mode = MODE_NEXT

    private var jumpGravity = JumpGravity.NONE

    private val anchor: Any?

    private var onStartListeners: MutableList<OnGuiderStartListener>?

    private var onStopListeners: MutableList<OnGuiderStopListener>?


    private val guides: List<Guide>

    private var guiderView: GuiderView? = null

    fun show(): Guider {
        if (anchor != null) {
            //检测锚点。
            val activity = initAnchor(anchor)
            //创建并初始化引导者View。
            initGuiderView(activity)
            //添加到DecorView中。
            add2Decor(activity, guiderView)
        } else {
            throw IllegalArgumentException("the Context of the view must be an Activity ")
        }
        return this
    }

    private fun add2Decor(activity: Activity?, guiderView: GuiderView?) {
        val root = activity!!.window.decorView as ViewGroup
        root.viewTreeObserver.addOnGlobalLayoutListener(guiderView)
        root.addView(
            guiderView, FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
        )
    }

    fun showInWindow(): Guider {
        if (anchor != null) {
            //检测锚点。
            val activity = initAnchor(anchor)
            //创建并初始化引导者View。
            initGuiderView(activity)
            //添加到当前Window中。
            add2Window(activity, guiderView)
        } else {
            throw NullPointerException("the anchor can not null ")
        }
        return this
    }

    private fun add2Window(activity: Activity?, guiderView: GuiderView?) {
        val window = activity!!.window
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
        window.addContentView(
            guiderView, ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
        )
    }

    private fun initAnchor(anchor: Any): Activity? {
        return if (anchor is Activity) {
            anchor
        } else if (anchor is Fragment) {
            anchor.activity
        } else if (anchor is View) {
            val view = anchor
            if (view.context is Activity) {
                view.context as Activity
            } else {
                throw IllegalArgumentException("the Context of the view must be an Activity ")
            }
        } else {
            throw IllegalArgumentException("the anchor's type must be Fragment or Activity or a view ")
        }
    }

    private fun initGuiderView(activity: Activity?): GuiderView {
        guiderView = GuiderView(activity!!)
        guiderView!!.setGuides(guides)
        guiderView!!.onGuiderStartListeners = onStartListeners
        guiderView!!.setOnGuiderStopListeners(onStopListeners)
        guiderView!!.mode = mode
        guiderView!!.jumpGravity = jumpGravity
        return guiderView!!
    }

    fun dismiss() {
        if (guiderView != null) {
            guiderView!!.dismiss()
            guiderView = null
        }
    }

    val isVisible: Boolean
        get() = guiderView != null && guiderView!!.isVisible

    fun addOnGuiderStartListener(listener: OnGuiderStartListener): Guider {
        if (onStartListeners == null) {
            onStartListeners = ArrayList()
        }
        onStartListeners!!.add(listener)
        return this
    }

    fun addOnGuiderStopListener(listener: OnGuiderStopListener): Guider {
        if (onStopListeners == null) {
            onStopListeners = ArrayList()
        }
        onStopListeners!!.add(listener)
        return this
    }

    class Builder {
        var anchor: Any? = null
        var onStartListeners: MutableList<OnGuiderStartListener> = ArrayList()
        var onStopListeners: MutableList<OnGuiderStopListener> = ArrayList()
        var guides: MutableList<Guide> = ArrayList()
        var mode = MODE_NEXT
        var jumpGravity = JumpGravity.NONE

        /**
         * 规定：如果有设置锚点，则把锚点作为容器。
         * 如果没有设置，则看目标point，如果point设置的是View，则把View所在context的decorView作为容器。
         *
         * @param anchor
         * @return
         */
        fun setAnchor(anchor: Any): Builder {
            this.anchor = anchor
            return this
        }

        fun addGuide(guide: Guide): Builder {
            guides.add(guide)
            return this
        }

        /**
         * 如果是NEXT模式的话，先添加的先显示。还有addGuide()函数也可以添加Guide。
         */
        fun addGuides(vararg guides: Guide): Builder {
            this.guides.addAll(listOf(*guides))
            return this
        }

        fun addOnGuiderStartListener(listener: OnGuiderStartListener): Builder {
            onStartListeners.add(listener)
            return this
        }

        fun addOnGuiderStopListener(listener: OnGuiderStopListener): Builder {
            onStopListeners.add(listener)
            return this
        }

        /**
         * Guider.MODE_NEXT表示一个接着一个显示，one by one.默认值。
         * Guider.MODE_TOGETHER表示多个Guide一起显示。
         */
        fun setMode(mode: Int): Builder {
            this.mode = mode
            return this
        }

        fun build(): Guider {
            return Guider(this)
        }

        fun show(): Guider {
            val guider = build()
            guider.show()
            return guider
        }

        fun showInWindow(): Guider {
            val guider = build()
            guider.showInWindow()
            return guider
        }

        fun jumpGravity(jumpGravity: JumpGravity): Builder {
            this.jumpGravity = jumpGravity
            return this
        }
    }

    init {
        anchor = builder.anchor
        onStartListeners = builder.onStartListeners
        onStopListeners = builder.onStopListeners
        guides = builder.guides
        mode = builder.mode
        jumpGravity = builder.jumpGravity
    }
}